/*
 * QTeXPreview
 * Copyright (C) 2008, Philip Pronin (philip.pronin@gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "flowLayout.h"
#include "tex.h"
#include "toolBox.h"

#include <QDomDocument>
#include <QFile>
#include <QProgressDialog>
#include <QTabWidget>
#include <QTextStream>
#include <QToolButton>

ToolButtonInfo::ToolButtonInfo(const ToolBoxCommand& _cmd, QObject* parent) :
	QObject(parent), cmd(_cmd) { }

const QString ToolBoxWidget::fileName = "config/toolbox.xml";

ToolBoxWidget::ToolBoxWidget(QWidget* parent) : QWidget(parent), editor(NULL) {
	tex = TeXFrontEnd::create(this);

	signalMapper = new QSignalMapper(this);
	connect(signalMapper, SIGNAL(mapped(QObject*)), SIGNAL(command(QObject*)));

	QVBoxLayout* mainLayout = new QVBoxLayout;
	mainLayout->setContentsMargins(0, 2, 0, 0);

	tabWidget = new QTabWidget;
	load();
	mainLayout->addWidget(tabWidget);

	setLayout(mainLayout);
}

void ToolBoxWidget::setEditor(TeXEditor* e) {
	editor = e;
}

void ToolBoxWidget::clear() {
	tabWidget->clear();
	foreach (QWidget* tab, tabs) delete tab;
	tabs.clear();
}

void ToolBoxWidget::load() {
	clear();

	QDomDocument doc("ToolBox");
	QFile file(fileName);
	if (!file.open(QFile::ReadOnly)) return;
	if (!doc.setContent(&file)) {
		file.close();
		return;
	}
	file.close();

	QDomElement root = doc.documentElement();
	if (root.tagName() != "toolbox") return;

	QDomElement groupEl = root.firstChildElement("tab");
	while (!groupEl.isNull()) {
		ToolBoxGroup group;
		group.active = groupEl.attribute("active", "yes") != "no";
		QString title = groupEl.firstChildElement("title").text();
		group.title = (title.isNull()) ? tr("[Untitled]") : title;

		QDomElement cmdEl = groupEl.firstChildElement("command");
		while (!cmdEl.isNull()) {
			ToolBoxCommand cmd;
			cmd.active = cmdEl.attribute("active", "yes") != "no";
			QString title = cmdEl.firstChildElement("title").text();
			cmd.title = (title.isNull()) ? tr("[Untitled]") : title;
			QDomElement texEl = cmdEl.firstChildElement("tex");
			cmd.tex = texEl.text();
			cmd.cursor = texEl.attribute("cursor", QString::number(cmd.tex.size())).toInt();
			cmd.image = cmdEl.firstChildElement("image").text();
			group.commands << cmd;

			cmdEl = cmdEl.nextSiblingElement("command");
		}

		groups << group;

		groupEl = groupEl.nextSiblingElement("tab");
	}

	populate();
}

void ToolBoxWidget::save() const {
	QFile file(fileName);
	if (!file.open(QFile::WriteOnly | QFile::Text)) return;

	QDomDocument doc("ToolBox");
	QDomElement root = doc.createElement("toolbox");
	root.setAttribute("version", "1");
	doc.appendChild(root);

	foreach(const ToolBoxGroup& group, groups) {
		QDomElement groupEl = doc.createElement("tab");
		groupEl.setAttribute("active", group.active ? "yes" : "no");
		QDomElement titleGrEl = doc.createElement("title");
		titleGrEl.appendChild(doc.createTextNode(group.title));
		groupEl.appendChild(titleGrEl);

		foreach(const ToolBoxCommand& cmd, group.commands) {
			QDomElement cmdEl = doc.createElement("command");
			cmdEl.setAttribute("active", cmd.active ? "yes" : "no");
			QDomElement titleCmdEl = doc.createElement("title");
			titleCmdEl.appendChild(doc.createTextNode(cmd.title));
			cmdEl.appendChild(titleCmdEl);
			QDomElement texEl = doc.createElement("tex");
			texEl.appendChild(doc.createTextNode(cmd.tex));
			texEl.setAttribute("cursor", cmd.cursor);
			cmdEl.appendChild(texEl);
			QDomElement imageEl = doc.createElement("image");
			imageEl.appendChild(doc.createTextNode(cmd.image));
			cmdEl.appendChild(imageEl);

			groupEl.appendChild(cmdEl);
		}

		root.appendChild(groupEl);
	}

	QTextStream ts(&file);
	ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	doc.save(ts, 2);
	file.close();
}

void ToolBoxWidget::populate() {
	int cnt = 0;
	foreach(const ToolBoxGroup& group, groups) if (group.active) {
		cnt++;
		foreach(const ToolBoxCommand& cmd, group.commands) if (cmd.active) cnt++;
	}

	QProgressDialog progress(tr("Rendering ToolBox images..."), 0, 0, 2 * cnt, this);
	progress.setWindowTitle(tr("Please wait..."));
	QIcon icon(QPixmap(":/main/16x16/text-x-tex.png"));
	progress.setWindowIcon(icon);
	#ifdef Q_WS_WIN
	progress.setMinimumDuration(500);
	#else //Q_WS_WIN
	progress.setMinimumDuration(1250);
	#endif //Q_WS_WIN

	cnt = 0;
	foreach(const ToolBoxGroup& group, groups) if (group.active) {
		progress.setValue(cnt++);

		FlowLayout* layout = new FlowLayout;
		QList<QPair<QIcon, int> > icons; int height = 16;
		int idx = 0;
		foreach(const ToolBoxCommand& cmd, group.commands) if (cmd.active) {
			QPixmap image; image.loadFromData(tex->renderNow(cmd.image));
			QIcon icon(image);
			icons << qMakePair(icon, image.width());
			height = qMax(height, image.height());
			idx++;

			progress.setValue(cnt++);
		}

		idx = 0;
		foreach(const ToolBoxCommand& cmd, group.commands) if (cmd.active) {
			QToolButton* btn = new QToolButton;
			connect(btn, SIGNAL(clicked()), signalMapper, SLOT(map()));
			signalMapper->setMapping(btn, new ToolButtonInfo(cmd, btn));
			btn->setIconSize(QSize(qMax(12, icons[idx].second), height));
			btn->setStatusTip(cmd.title);
			btn->setToolTip(QString("<strong>%1</strong><br>%2").arg(cmd.title, cmd.tex));
			btn->setIcon(icons[idx].first);
			layout->addWidget(btn);
			idx++;

			progress.setValue(cnt++);
		}

		QWidget* widget = new QWidget();
		widget->setLayout(layout);
		tabWidget->addTab(widget, group.title);
		tabs.push_back(widget);
	}

	resizeEvent(NULL);
	progress.setValue(cnt++);
}

void ToolBoxWidget::configure() {
	ToolBoxConfig tbc(this);
	tbc.setGroupList(groups);
	if (tbc.exec() == QDialog::Accepted) {
		groups = tbc.getGroupList();
		save();
		clear();
		populate();
	}
}
